package cn.sunyblog.tool.threadpool;

import cn.sunyblog.tool.threadpool.monitor.ThreadPoolMonitor;
import cn.sunyblog.tool.threadpool.monitor.ThreadPoolMetrics;
import cn.sunyblog.tool.threadpool.strategy.AdjustmentStrategy;
import cn.sunyblog.tool.threadpool.queue.DynamicBlockingQueue;
import cn.sunyblog.tool.threadpool.config.DynamicThreadPoolConfig;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 动态线程池执行器
 * 支持根据任务负载动态调整线程池参数
 * 
 * @author sunyblog
 */
public class DynamicThreadPoolExecutor extends ThreadPoolExecutor {
    
    private final DynamicThreadPoolConfig config;
    private final ThreadPoolMonitor monitor;
    private final AdjustmentStrategy adjustmentStrategy;
    private final AtomicBoolean adjusting = new AtomicBoolean(false);
    private final AtomicLong lastAdjustTime = new AtomicLong(System.currentTimeMillis());
    
    // 监控指标
    private final AtomicLong submittedTaskCount = new AtomicLong(0);
    private final AtomicLong completedTaskCount = new AtomicLong(0);
    
    public DynamicThreadPoolExecutor(DynamicThreadPoolConfig config) {
        super(
            config.getCorePoolSize(),
            config.getMaximumPoolSize(),
            config.getKeepAliveTime(),
            config.getTimeUnit(),
            new DynamicBlockingQueue<>(config.getQueueCapacity()),
            config.getThreadFactory(),
            config.getRejectedExecutionHandler()
        );
        
        this.config = config;
        this.monitor = new ThreadPoolMonitor(this);
        this.adjustmentStrategy = config.getAdjustmentStrategy();
        
        // 启动监控和调整任务
        startMonitoring();
    }
    
    /**
     * 便捷构造函数 - 直接指定策略
     */
    public DynamicThreadPoolExecutor(
            int corePoolSize,
            int maximumPoolSize,
            long keepAliveTime,
            TimeUnit unit,
            int queueCapacity,
            AdjustmentStrategy strategy,
            String poolName) {
        super(
            corePoolSize,
            maximumPoolSize,
            keepAliveTime,
            unit,
            new DynamicBlockingQueue<>(queueCapacity),
            new ThreadFactory() {
                private int counter = 0;
                @Override
                public Thread newThread(Runnable r) {
                    Thread t = new Thread(r, poolName + "-thread-" + (++counter));
                    t.setDaemon(false);
                    return t;
                }
            },
            new RejectedExecutionHandler() {
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    // 记录拒绝的任务
                    if (executor instanceof DynamicThreadPoolExecutor) {
                        DynamicThreadPoolExecutor dynamicExecutor = (DynamicThreadPoolExecutor) executor;
                        dynamicExecutor.recordTaskRejection();
                    }
                    // 抛出异常
                    throw new RejectedExecutionException(
                        "Task " + r.toString() + " rejected from " + executor.toString());
                }
            }
        );
        
        // 创建默认配置
        this.config = new DynamicThreadPoolConfig();
        this.config.setThreadPoolName(poolName);
        this.config.setCorePoolSize(corePoolSize);
        this.config.setMaximumPoolSize(maximumPoolSize);
        this.config.setKeepAliveTime(keepAliveTime);
        this.config.setTimeUnit(unit);
        this.config.setQueueCapacity(queueCapacity);
        this.config.setMonitorInterval(2); // 2秒监控间隔
        this.config.setEnableMetricsLogging(true);
        
        this.monitor = new ThreadPoolMonitor(this);
        this.adjustmentStrategy = strategy;
        
        // 启动监控和调整任务
        startMonitoring();
    }
    
    @Override
    public void execute(Runnable command) {
        submittedTaskCount.incrementAndGet();
        monitor.recordTaskSubmission();
        // 包装任务以记录提交时间
        TaskWrapper wrapper = new TaskWrapper(command);
        super.execute(wrapper);
    }
    
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        completedTaskCount.incrementAndGet();
        monitor.recordTaskCompletion();
    }
    
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        // 记录任务开始执行时间，计算等待时间
        if (r instanceof TaskWrapper) {
            TaskWrapper wrapper = (TaskWrapper) r;
            long waitTime = System.currentTimeMillis() - wrapper.getSubmitTime();
            monitor.recordTaskWaitTime(waitTime);
        }
    }
    
    /**
     * 启动监控任务
     */
    private void startMonitoring() {
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread t = new Thread(r, "DynamicThreadPool-Monitor");
            t.setDaemon(true);
            return t;
        });
        
        scheduler.scheduleAtFixedRate(this::monitorAndAdjust, 
            config.getMonitorInterval(), 
            config.getMonitorInterval(), 
            TimeUnit.SECONDS);
    }
    
    /**
     * 监控并调整线程池参数
     */
    private void monitorAndAdjust() {
        try {
            // 获取当前指标
            ThreadPoolMetrics metrics = monitor.getMetrics();
            
            // 判断是否需要调整
            if (shouldAdjust(metrics)) {
                adjustThreadPool(metrics);
            }
            
            // 记录监控日志
            logMetrics(metrics);
            
        } catch (Exception e) {
            System.err.println("监控调整过程中发生异常: " + e.getMessage());
            e.printStackTrace();
        }
    }
    

    
    /**
     * 判断是否需要调整
     */
    private boolean shouldAdjust(ThreadPoolMetrics metrics) {
        // 如果正在调整中，跳过
        if (adjusting.get()) {
            return false;
        }
        
        // 获取调整建议
        AdjustmentStrategy.AdjustmentRecommendation recommendation = adjustmentStrategy.recommend(metrics);
        if (recommendation == null) {
            return false;
        }
        
        // 根据调整类型设置不同的间隔限制
        long currentTime = System.currentTimeMillis();
        long timeSinceLastAdjust = currentTime - lastAdjustTime.get();
        
        // 紧急扩容：最小间隔10秒
        if (recommendation.getType() == AdjustmentStrategy.AdjustmentType.EMERGENCY) {
            if (timeSinceLastAdjust < 10 * 1000) {
                System.out.println(String.format("[%s] 紧急扩容间隔未到，跳过调整。距离上次调整: %d秒", 
                    config.getThreadPoolName(), timeSinceLastAdjust / 1000));
                return false;
            }
            return true;
        }
        
        // 常规扩容：最小间隔30秒
        if (recommendation.getType() == AdjustmentStrategy.AdjustmentType.SCALE_UP) {
            if (timeSinceLastAdjust < 30 * 1000) {
                System.out.println(String.format("[%s] 常规扩容间隔未到，跳过调整。距离上次调整: %d秒", 
                    config.getThreadPoolName(), timeSinceLastAdjust / 1000));
                return false;
            }
            return true;
        }
        
        // 缩容和优化：使用配置的最小间隔
        if (timeSinceLastAdjust < config.getMinAdjustmentInterval() * 1000) {
            return false;
        }
        
        return true;
    }
    
    /**
     * 调整线程池参数
     */
    private void adjustThreadPool(ThreadPoolMetrics metrics) {
        if (!adjusting.compareAndSet(false, true)) {
            return;
        }
        
        try {
            AdjustmentStrategy.AdjustmentRecommendation recommendation = adjustmentStrategy.recommend(metrics);
            
            if (recommendation != null) {
                boolean adjusted = false;
                
                // 智能调整线程池参数：根据扩容/缩容类型决定调整顺序
                boolean isScaleDown = recommendation.getType() == AdjustmentStrategy.AdjustmentType.SCALE_DOWN;
                int currentCore = getCorePoolSize();
                int currentMax = getMaximumPoolSize();
                int newCore = recommendation.getNewCorePoolSize();
                int newMax = recommendation.getNewMaximumPoolSize();
                
                if (isScaleDown) {
                    // 缩容：先减少核心线程数，再减少最大线程数
                    if (newCore != currentCore) {
                        setCorePoolSize(newCore);
                        String adjustMsg = String.format(
                            "调整核心线程数: %d -> %d (%s)", 
                            currentCore, newCore, recommendation.getReason());
                        System.out.println(String.format("[%s] %s", config.getThreadPoolName(), adjustMsg));
                        
                        try {
                            cn.sunyblog.tool.threadpool.web.ThreadPoolWebController.addAdjustmentHistory(
                                config.getThreadPoolName(), adjustMsg);
                        } catch (Exception ignored) {}
                        adjusted = true;
                    }
                    
                    if (newMax != currentMax) {
                        setMaximumPoolSize(newMax);
                        String adjustMsg = String.format(
                            "调整最大线程数: %d -> %d (%s)", 
                            currentMax, newMax, recommendation.getReason());
                        System.out.println(String.format("[%s] %s", config.getThreadPoolName(), adjustMsg));
                        
                        try {
                            cn.sunyblog.tool.threadpool.web.ThreadPoolWebController.addAdjustmentHistory(
                                config.getThreadPoolName(), adjustMsg);
                        } catch (Exception ignored) {}
                        adjusted = true;
                    }
                } else {
                    // 扩容：先增加最大线程数，再增加核心线程数
                    if (newMax != currentMax) {
                        setMaximumPoolSize(newMax);
                        String adjustMsg = String.format(
                            "调整最大线程数: %d -> %d (%s)", 
                            currentMax, newMax, recommendation.getReason());
                        System.out.println(String.format("[%s] %s", config.getThreadPoolName(), adjustMsg));
                        
                        try {
                            cn.sunyblog.tool.threadpool.web.ThreadPoolWebController.addAdjustmentHistory(
                                config.getThreadPoolName(), adjustMsg);
                        } catch (Exception ignored) {}
                        adjusted = true;
                    }
                    
                    if (newCore != currentCore) {
                        setCorePoolSize(newCore);
                        String adjustMsg = String.format(
                            "调整核心线程数: %d -> %d (%s)", 
                            currentCore, newCore, recommendation.getReason());
                        System.out.println(String.format("[%s] %s", config.getThreadPoolName(), adjustMsg));
                        
                        try {
                            cn.sunyblog.tool.threadpool.web.ThreadPoolWebController.addAdjustmentHistory(
                                config.getThreadPoolName(), adjustMsg);
                        } catch (Exception ignored) {}
                        adjusted = true;
                    }
                }
                
                // 调整队列大小
                if (recommendation.getNewQueueCapacity() > 0) {
                    DynamicBlockingQueue<?> queue = (DynamicBlockingQueue<?>) getQueue();
                    int oldCapacity = queue.getCapacity();
                    if (recommendation.getNewQueueCapacity() != oldCapacity) {
                        queue.setCapacity(recommendation.getNewQueueCapacity());
                        String adjustMsg = String.format(
                            "调整队列大小: %d -> %d (%s)", 
                            oldCapacity, recommendation.getNewQueueCapacity(),
                            recommendation.getReason());
                        System.out.println(String.format("[%s] %s", config.getThreadPoolName(), adjustMsg));
                        
                        // 记录到Web控制器
                        try {
                            cn.sunyblog.tool.threadpool.web.ThreadPoolWebController.addAdjustmentHistory(
                                config.getThreadPoolName(), adjustMsg);
                        } catch (Exception ignored) {}
                        
                        adjusted = true;
                    }
                }
                
                if (adjusted) {
                    lastAdjustTime.set(System.currentTimeMillis());
                    
                    // 更新拒绝任务基准值，确保下次显示的是新的拒绝任务数
                    monitor.updateRejectedTaskBaseline();
                    
                    System.out.println(String.format(
                        "[%s] 线程池调整完成 - %s", 
                        config.getThreadPoolName(), recommendation.getType().getDescription()));
                }
            }
            
        } catch (Exception e) {
            System.err.println("调整线程池参数时发生异常: " + e.getMessage());
            e.printStackTrace();
        } finally {
            adjusting.set(false);
        }
    }
    
    /**
     * 记录监控指标
     */
    private void logMetrics(ThreadPoolMetrics metrics) {
        if (config.isEnableMetricsLogging()) {
            System.out.println(String.format(
                "[ThreadPool-Metrics] 核心线程数: %d, 最大线程数: %d, 活跃线程数: %d, 队列大小: %d/%d, " +
                "队列使用率: %.2f%%, 线程活跃度: %.2f%%, 提交速率: %.2f/s, 完成速率: %.2f/s, 平均等待时间: %.2fms",
                getCorePoolSize(),
                getMaximumPoolSize(),
                getActiveCount(),
                getQueue().size(),
                ((DynamicBlockingQueue<?>) getQueue()).getCapacity(),
                metrics.getQueueUsageRate() * 100,
                metrics.getThreadPoolActivity() * 100,
                metrics.getTaskSubmitRate(),
                metrics.getTaskCompleteRate(),
                metrics.getAverageWaitTime()
            ));
        }
    }
    
    /**
     * 获取当前监控指标
     */
    public ThreadPoolMetrics getCurrentMetrics() {
        return monitor.getMetrics();
    }
    
    /**
     * 获取调整统计信息
     */
    public String getAdjustmentStats() {
        return String.format(
            "最后调整时间: %s",
            new java.util.Date(lastAdjustTime.get())
        );
    }
    
    /**
     * 记录任务拒绝
     */
    public void recordTaskRejection() {
        monitor.recordTaskRejection();
    }
    
    /**
     * 获取配置信息
     */
    public DynamicThreadPoolConfig getConfig() {
        return config;
    }
    
    /**
     * 获取调整策略
     */
    public AdjustmentStrategy getAdjustmentStrategy() {
        return adjustmentStrategy;
    }
    
    @Override
    public void shutdown() {
        super.shutdown();
        System.out.println("动态线程池已关闭");
    }
}